package com.qt;

import com.qt.entity.Author;
import com.qt.entity.Book;
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;

import java.util.*;
import java.util.function.*;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class StreamDemo01 {

    public static void main(String[] args) {

        test25();
        //test24();
//        test23();

//        List<Author> authors = getAuthors();
//        //System.out.println(authors);
//
//        Stream<Author> stream = authors.stream();
//        test22();
        //test21();
        //test20();
        //test19();
        //test18();
        //test13();
        //test12();
        //test11();
//        test10();
        //test09();
        //test08();
        //test07();
        //test06();
        //test05();
        //test04();
        //test03();

        //test02();



        //1.我们可以调用getAuthors方法获取到作家的集合。现在需要打印所有年龄小于18的作家的名字,并且要注意去重。
        //ctrl + alt + m 抽取方法
        //test01(authors);




    }

    private static void test25() {
        /**
         * 并行流
         */
        Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        Integer sum = stream.parallel()
                .peek(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer num) {
                        System.out.println(num + ":" +Thread.currentThread().getName());
                    }
                })
                .filter(num -> num > 5)
                .reduce((result, ele) -> result + ele)
                .get();
        System.out.println(sum);

        getAuthors().parallelStream()
                .map(author -> author.getName())
                .forEach(name -> System.out.println(name));



    }

    private static void test24() {
        List<Author> authors = getAuthors();
        authors.stream()
                .map(author -> author.getAge())
                .map(age -> age + 10)
                .filter(age->age>18)
                .map(age->age+2)
                .forEach(System.out::println);

        authors.stream()
                .mapToInt(author -> author.getAge())
                .map(age -> age + 10)
                .filter(age->age>18)
                .map(age->age+2)
                .forEach(System.out::println);


    }

    private static void test23() {
        List<Author> authors = getAuthors();
        authors.stream()
                .map(Author::getName)
                .map(StringBuilder::new)
                .map(sb->sb.append("-三更").toString())
                .forEach(System.out::println);

    }

    private static void test22() {

        /**
         * 	使用reduce求所有作者中年龄的最大值
         *
         * 		使用reduce求所有作者中年龄的最小值
         */
        Integer max = getAuthors().stream()
                .map(author -> author.getAge())
                .reduce(Integer.MIN_VALUE, (result, element) -> result > element ? result : element);
        System.out.println(max);

        Integer min = getAuthors().stream()
                .map(author -> author.getAge())
                .reduce(Integer.MAX_VALUE, (result, element) -> result > element ? element : result);
        System.out.println(min);

        Optional<Integer> reduce = getAuthors().stream()
                .map(author -> author.getAge())
                .reduce(new BinaryOperator<Integer>() {
                    @Override
                    public Integer apply(Integer result, Integer element) {
                        return result > element ? element : result;
                    }
                });
        reduce.ifPresent(age -> System.out.println(age));

    }

    private static void test21() {

        /**
         * 例子：
         * ​	使用reduce求所有作者年龄的和
         */
        Integer reduce = getAuthors().stream()
                .distinct()
                .map(author -> author.getAge())
                .reduce(0, (result, integer2) -> result + integer2);
        System.out.println(reduce);

    }

    private static void test20() {
        /**
         * ###### findAny
         * ​	获取流中的任意一个元素。该方法没有办法保证获取的一定是流中的第一个元素。
         * 例子：
         * ​	获取任意一个年龄大于18的作家，如果存在就输出他的名字
         *
         * ###### findFirst
         *
         * ​	获取流中的第一个元素。
         * 例子：
         * ​	获取一个年龄最小的作家，并输出他的姓名。
         *
         */
//        Optional<Author> any = getAuthors().stream()
//                .filter(author -> author.getAge() > 18)
//                .findAny();
//
//        any.ifPresent(author -> System.out.println(author.getName()));
        Optional<Author> first = getAuthors().stream()
                .sorted(new Comparator<Author>() {
                    @Override
                    public int compare(Author o1, Author o2) {
                        return o1.getAge() - o2.getAge();
                    }
                })
                .findFirst();
        first.ifPresent(author -> System.out.println(author.getName()));


    }

    private static void test19() {
        /**
         * ###### anyMatch
         *
         * ​	可以用来判断是否有任意符合匹配条件的元素，结果为boolean类型。
         *例子：
         * ​	判断是否有年龄在29以上的作家
         *
         * ###### allMatch
         *
         * ​	可以用来判断是否都符合匹配条件，结果为boolean类型。如果都符合结果为true，否则结果为false。
         * 例子：
         * ​	判断是否所有的作家都是成年人
         *
         */
        boolean b = getAuthors().stream()
                .anyMatch(new Predicate<Author>() {
                    @Override
                    public boolean test(Author author) {
                        return author.getAge() > 29;
                    }
                });

        boolean b1 = getAuthors().stream()
                .allMatch(author -> author.getAge() >= 18);
        boolean b2 = getAuthors().stream()
                .noneMatch(author -> author.getAge() > 100);


    }

    private static void test18() {
        /**
         * ###### anyMatch
         * ​	可以用来判断是否有任意符合匹配条件的元素，结果为boolean类型。
         * 例子：
         * ​	判断是否有年龄在29以上的作家
         */
        boolean b = getAuthors().stream()
                .anyMatch(new Predicate<Author>() {
                    @Override
                    public boolean test(Author author) {
                        return author.getAge() > 19;
                    }
                });
        System.out.println(b);

    }

    private static void test13() {
        /**
         * ##### collect
         * ​	把当前流转换成一个集合。
         * 例子：
         * ​	获取一个存放所有作者名字的List集合。
         *
         * 获取一个所有书名的Set集合。
         *
         * 获取一个Map集合，map的key为作者名，value为List<Book>
         *
         */
        List<Author> authors = getAuthors();
//        List<String> collect = authors.stream()
//                .map(author -> author.getName())
//                .distinct()
//                .collect(Collectors.toList());
//        System.out.println(collect);

//        Set<String> collect = authors.stream()
//                .distinct()
//                .flatMap(author -> author.getBooks().stream())
//                .distinct()
//                .map(book -> book.getName())
//                .collect(Collectors.toSet());
//        System.out.println(collect);
        Map<String, List<Book>> collect = authors.stream()
                .distinct()
                .collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks()));
        System.out.println(collect);


    }

    private static void test12() {
        /**
         * ##### count
         * 	可以用来获取当前流中元素的个数。
         * 例子：
         * 	打印这些作家的所出书籍的数目，注意删除重复元素。
         * ##### max&min
         * 	可以用来或者流中的最值。
         * 例子：
         * 	分别获取这些作家的所出书籍的最高分和最低分并打印。
         */
        Stream<Author> stream = getAuthors().stream();
//        long count = stream.flatMap(author -> author.getBooks().stream())
//                .distinct()
//                .count();
//        System.out.println(count);
        Optional<Integer> max = stream.flatMap(author -> author.getBooks().stream())
                .map(book -> book.getScore())
                .min((stcop1, stcop2) -> stcop2 - stcop1);
        System.out.println(max.get());


    }

    private static void test11() {
        //例二：
        //打印现有数据的所有分类。要求对分类进行去重。不能出现这种格式：哲学,爱情
        List<Author> authors = getAuthors();
        authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .flatMap(book -> Arrays.stream(book.getCategory().split(",")))
                .distinct()
                .forEach(category -> System.out.println(category));

    }

    private static void test10() {
        /**
         * map只能把一个对象转换成另一个对象来作为流中的元素。而flatMap可以把一个对象转换成多个对象作为流中的元素。
         * 例一：
         * 	打印所有书籍的名字。要求对重复的元素进行去重。
         */
        List<Author> authors = getAuthors();
        authors.stream()
                .flatMap((Function<Author, Stream<Book>>) author -> author.getBooks().stream())
                .distinct()
                .forEach(book -> System.out.println(book.getName()));


    }

    private static void test09() {
        /**
         * ##### skip
         * 	跳过流中的前n个元素，返回剩下的元素
         * 例如：
         * 	打印除了年龄最大的作家外的其他作家，要求不能有重复元素，并且按照年龄降序排序。
         */
        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .sorted((o1, o2) -> o2.getAge() - o1.getAge())
                .skip(1)
                .forEach(author -> System.out.println(author.getName() + ":" + author.getAge()));

    }

    private static void test08() {

        /**
         * ##### limit
         *
         * 可以设置流的最大长度，超出的部分将被抛弃。
         * 例如：
         * 对流中的元素按照年龄进行降序排序，并且要求不能有重复的元素,然后打印其中年龄最大的两个作家的姓名。
         */
        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .sorted((o1, o2) -> {return o2.getAge() - o1.getAge();})
                .limit(2)
                .forEach(author -> System.out.println(author.getName() + ":" + author.getAge() ));
    }

    private static void test07() {

        /**
         * ##### sorted
         * 可以对流中的元素进行排序。
         * 例如：
         * 对流中的元素按照年龄进行降序排序，并且要求不能有重复的元素。
         */
        List<Author> authors = getAuthors();
        Stream<Author> stream = authors.stream();
//        stream.distinct()
//                .sorted()
//                .forEach(author -> System.out.println(author));
        stream.distinct()
                .sorted((o1, o2) -> o1.getAge() - o2.getAge())
                .forEach(author -> System.out.println(author));

    }

    private static void test06() {
        /**
         * ##### distinct
         * 可以去除流中的重复元素。
         * 例如：
         * 打印所有作家的姓名，并且要求其中不能有重复元素。
         * 注意：distinct方法是依赖Object的equals方法来判断是否是相同对象的。所以需要注意重写equals方法。
         */

        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .forEach(author -> System.out.println(author.getName()));


    }

    private static void test05() {
        /**
         *  map
         *
         可以把对流中的元素进行计算或转换。
         * 例如：
         * 	打印所有作家的姓名
         */
        List<Author> authors = getAuthors();
//        authors.stream()
//                .map(author -> author.getName())
//                .forEach(s -> System.out.println(s));
//        authors.stream()
//                .distinct()
//                .map(author -> author.getAge())
//                .map(integer -> integer + 10)
//                .forEach(integer -> System.out.println(integer));

        authors.stream()
                .map(author -> author.getAge())
                .map(age -> age + 10)
                .forEach(age -> System.out.println(age));

    }

    private static void test04() {
        //打印所有姓名长度大于1的作家的姓名
        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .filter(author -> author.getName().length() > 1)
                .forEach(author -> System.out.println(author));


    }

    private static void test03() {

        Map<String,Integer> map = new HashMap<>();
        map.put("蜡笔小新",19);
        map.put("黑子",17);
        map.put("日向翔阳",16);

        Set<Map.Entry<String, Integer>> entries = map.entrySet();
        Stream<Map.Entry<String, Integer>> stream = entries.stream();

        stream.distinct()
                .filter(entry -> entry.getValue() > 15)
                .forEach(entry -> System.out.println("结果大于15的：" + entry));


    }

    private static void test02() {

        Integer[] arr = {1,2,3,4,5};
        //Stream<Integer> stream = Arrays.stream(arr);
        Stream<Integer> stream = Stream.of(arr);
        stream.distinct()
                .filter(integer -> integer > 2)
                .forEach(integer -> System.out.println(integer));

    }

    private static void test01(List<Author> authors) {
        authors.stream()
                .distinct()
                .filter(author -> author.getAge() < 18)
                .forEach(author -> System.out.println(author.getName()));
    }


    private static List<Author> getAuthors() {
        //数据初始化
        Author author = new Author(1L,"蒙多",33,"一个从菜刀中明悟哲理的祖安人",null);
        Author author2 = new Author(2L,"亚拉索",15,"狂风也追逐不上他的思考速度",null);
        Author author3 = new Author(3L,"易",14,"是这个世界在限制他的思维",null);
        Author author4 = new Author(3L,"易",14,"是这个世界在限制他的思维",null);

        //书籍列表
        List<Book> books1 = new ArrayList<>();
        List<Book> books2 = new ArrayList<>();
        List<Book> books3 = new ArrayList<>();

        books1.add(new Book(1L,"刀的两侧是光明与黑暗","哲学,爱情",88,"用一把刀划分了爱恨"));
        books1.add(new Book(2L,"一个人不能死在同一把刀下","个人成长,爱情",99,"讲述如何从失败中明悟真理"));

        books2.add(new Book(3L,"那风吹不到的地方","哲学",85,"带你用思维去领略世界的尽头"));
        books2.add(new Book(3L,"那风吹不到的地方","哲学",85,"带你用思维去领略世界的尽头"));
        books2.add(new Book(4L,"吹或不吹","爱情,个人传记",56,"一个哲学家的恋爱观注定很难把他所在的时代理解"));

        books3.add(new Book(5L,"你的剑就是我的剑","爱情",56,"无法想象一个武者能对他的伴侣这么的宽容"));
        books3.add(new Book(6L,"风与剑","个人传记",100,"两个哲学家灵魂和肉体的碰撞会激起怎么样的火花呢？"));
        books3.add(new Book(6L,"风与剑","个人传记",100,"两个哲学家灵魂和肉体的碰撞会激起怎么样的火花呢？"));

        author.setBooks(books1);
        author2.setBooks(books2);
        author3.setBooks(books3);
        author4.setBooks(books3);

        List<Author> authorList = new ArrayList<>(Arrays.asList(author,author2,author3,author4));
        return authorList;
    }

}
